/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include <aos/kv.h>
#include <kvset.h>
#include "wm_internal_flash.h"

extern int __kv_setdata(char *key, char *buf, int bufsize);
extern int __kv_getdata(char *key, char *buf, int bufsize);
extern int __kv_del(char *key);
extern int __kv_reset(void);

int aos_kv_set(const char *key, void *value, int len, int sync)
{
    return __kv_setdata((char *)key, value, len);
}

int aos_kv_setstring(const char *key, const char *v)
{
    return __kv_setdata((char *)key, (void *)v, strlen(v));
}

int aos_kv_setfloat(const char *key, float v)
{
    return __kv_setdata((char *)key, (void *)&v, sizeof(v));
}

int aos_kv_setint(const char *key, int v)
{
    return __kv_setdata((char *)key, (void *)&v, sizeof(v));
}

int aos_kv_get(const char *key, void *buffer, int *buffer_len)
{
    if (buffer_len) {
        int ret = __kv_getdata((char *)key, buffer, *buffer_len);

        if (ret > 0) {
            *buffer_len = ret;
        }

        return (ret <= 0) ? -1 : 0;
    }

    return -1;
}

int aos_kv_getstring(const char *key, char *value, int len)
{
    int ret;
    ret = __kv_getdata((char *)key, (char *)value, len - 1);

    if(ret > 0) {
        value[ret < len ? ret : len - 1] = '\0';
    }

    return ret;
}

int aos_kv_getfloat(const char *key, float *value)
{
    int ret = __kv_getdata((char *)key, (char *)value, sizeof(float));
    return (ret == sizeof(float)) ? 0 : -1;
}

int aos_kv_getint(const char *key, int *value)
{
    int ret = __kv_getdata((char *)key, (char *)value, sizeof(int));
    return (ret == sizeof(int)) ? 0 : -1;
}

int aos_kv_del(const char *key)
{
    return __kv_del((char *)key);
}

int aos_kv_reset(void)
{
    return __kv_reset();
}

static kv_t g_kv;

static int kv_flash_erase(kv_t *kv, int pos, int size)
{
    // printf("---> %s\r\n",__func__);
    // printf("---> handle:%d, pos:0x%08X, size:%d\n", kv->handle, pos, size);
    // printf("---> kv->mem:0x%08X\n", kv->mem);

    if (pos < 0) {
        return -22;
    }
    if(pos/4096 <= kv->num)
    {
        int sector = (pos + (int)kv->mem)/4096;
        return tls_fls_erase(sector);
    }
    else
    {
        printf("---> erase error\n");
        return -22;
    }
}

static int kv_flash_write(kv_t *kv, int pos, void *data, int size)
{
    // printf("---> %s\r\n",__func__);
    // printf("---> handle:%d, pos:0x%08X, size:%d\n", kv->handle, pos, size);

    if (pos >= 0 && (pos + size)/4096 <= kv->num) {
        int addr = pos + (int)kv->mem;
        return tls_fls_write(addr, data, size);
    }
    else
    {
        printf("---> write error\n");
        return -22;
    }
}

static int kv_flash_read(kv_t *kv, int pos, void *data, int size)
{
    // printf("---> %s\r\n",__func__);
    // printf("---> handle:%d, pos:0x%08X, size:%d\n", kv->handle, pos, size);
    int ret;
    if (pos < 0 || data == NULL) {
        printf("---> read error\n");
        ret = -22;
    }
    if ((pos + size) <= kv->num*4096) {
        int addr = pos + (int)kv->mem;
        return tls_fls_read(addr, data, size);
    }
    return ret;
}

static flash_ops_t flash_ops = {
    .write = kv_flash_write,
    .erase = kv_flash_erase,
    .read = kv_flash_read
};

/**System parameter, default for 2M flash*/
// unsigned int  TLS_FLASH_END_ADDR             =        (0x81FFFFFUL);
// 4K
// unsigned int  TLS_FLASH_OTA_FLAG_ADDR        =        (0x81FF000UL);
// 4K
// unsigned int  TLS_FLASH_PARAM_RESTORE_ADDR   =        (0x81FE000UL);
// 4K
// unsigned int  TLS_FLASH_PARAM2_ADDR          =        (0x81FD000UL);
// 4k
// unsigned int  TLS_FLASH_PARAM1_ADDR          =        (0x81FC000UL);
// 4K
// unsigned int  TLS_FLASH_PARAM_DEFAULT        =        (0x81FB000UL);
// 32K
// key-value 仓库开始地址                                 (0x81F4000UL);
int kv2x_init(kv_t *kv, const char *partition)
{
    // printf("---> %s\r\n",__func__);
    memset(kv, 0, sizeof(kv_t));
    kv->handle = 0;
    kv->ops    = &flash_ops;
    uint8_t *mem        = (uint8_t *)((0x81F3000UL));                       // key-value 仓库开始地址
    int      block_size = 4096;                                             // flash sector大小为4K             
    int      block_num  = 32*1024/4096;                                     // 32K/4K=8 sector

    // printf("---> handle:%d\n",kv->handle);
    // printf("---> mem:0x%08X\n",mem);
    // printf("---> block_num:%d\n",block_num);
    // printf("---> block_size:%d\n",block_size);

    kv_init(kv, mem, block_num, block_size);

    return 0;
}

int aos_kv_init(const char *partname)
{
    printf("---> %s\r\n",__func__);
    if (kv2x_init(&g_kv, partname) < 0) {
        g_kv.handle = -1;
        return -1;
    }
    return 0;
}


int __kv_setdata(char *key, char *buf, int bufsize)
{
    
    if (g_kv.handle < 0) {
        return -1;
    }
    // printf("bufsize:%d\n",bufsize);
    tls_flash_unlock();
    int ret = kv_set(&g_kv, key, buf, bufsize) >= 0 ? 0 : -1;
    tls_flash_lock();

    return ret;
}

int __kv_getdata(char *key, char *buf, int bufsize)
{
    if (g_kv.handle < 0) {
        return -1;
    }

    if (key == NULL || buf == NULL || bufsize <= 0)
        return -1;
    tls_flash_unlock();
    int ret = kv_get(&g_kv, key, buf, bufsize);
    tls_flash_lock();

    return ret;
}

int __kv_del(char *key)
{
    if (g_kv.handle < 0) {
        return -1;
    }

    tls_flash_unlock();
    int ret = kv_rm(&g_kv, key);
    tls_flash_lock();

    return ret;
}

int __kv_reset(void)
{
    if (g_kv.handle < 0) {
        return -1;
    }

    tls_flash_unlock();
    int ret = kv_reset(&g_kv);
    tls_flash_lock();

    return ret;
}

void __kv_dump()
{
    if (g_kv.handle < 0) {
        return;
    }

    tls_flash_unlock();
    kv_dump(&g_kv);
    tls_flash_lock();
}

void __show_data()
{
    if (g_kv.handle < 0) {
        return;
    }

    tls_flash_unlock();
    kv_show_data(&g_kv);
    tls_flash_lock();
}

static int _iter_list(kvnode_t *node, void *p)
{
    printf("%s: %s\n", \
           KVNODE_OFFSET2CACHE(node, head_offset),
           KVNODE_OFFSET2CACHE(node, value_offset)
          );
    return 0;
}

struct kv_foreach_func_t {
    void (*func)(char *key, char *val, uint16_t val_size, void *arg);
    void *arg;
};

static int _iter_foreach(kvnode_t *node, void *p)
{
    struct kv_foreach_func_t *func = p;

    if (func && func->func) {
        func->func((char *)KVNODE_OFFSET2CACHE(node, head_offset), (char *)KVNODE_OFFSET2CACHE(node, value_offset), node->val_size, func->arg);
    }
    return 0;
}

void __kv_foreach(void (*func)(char *key, char *val, uint16_t val_size, void *arg), void *arg)
{
    if (g_kv.handle < 0) {
        return;
    }

    struct kv_foreach_func_t cb_func = {0};
    cb_func.func = func;
    cb_func.arg = arg;

    tls_flash_unlock();
    kv_iter(&g_kv, _iter_foreach, &cb_func);
    tls_flash_lock();
}

void __kv_list()
{
    if (g_kv.handle < 0) {
        return;
    }

    tls_flash_unlock();
    kv_iter(&g_kv, _iter_list, NULL);
    tls_flash_lock();
}

/**
 * This function will get data from the factory setting area.
 *
 * @param[in]   key   the data pair of the key, less than 64 bytes
 * @param[in]   size  the size of the buffer
 * @param[out]  buf   the buffer that will store the data
 * @return  the length of the data value, error code otherwise
 */
int nvram_get_val(const char *key, void *buf, int size)
{
    memset(buf, 0, size);

    return __kv_getdata((char *)key, buf, size - 1);
}

/**
 * This function will set data to the factory setting area.
 *
 * @param[in]   key   the data pair of the key, less than 64 bytes
 * @param[in]   value the data pair of the value, delete the pair if value == NULL
 * @return  the length of the data value, error code otherwise
 */
int nvram_set_val(const char *key, char *value)
{
    tls_flash_unlock();
    int ret = kv_set(&g_kv, key, value, strlen(value));
    tls_flash_lock();

    return ret;
}